//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "math.h"

#define FC_RAND_MAX			0x7FFF
#define FC_RAND_MAX32		0x7FFFFFFF
#define FC_INV_RAND_MAX		0.00003052f // 1/0x7fff

FC_NAMESPACE_BEGIN


namespace internal
{
	// basic rand implementation.
	template <class Proxy>
	struct rand_holder
	{
		static int rand_seed;
	};

	template <class T> int rand_holder<T>::rand_seed = 0;

	inline int rand()
	{
		return(((rand_holder<void>::rand_seed =
			rand_holder<void>::rand_seed * 214013 + 2531011) >> 16) & FC_RAND_MAX);
	}

	inline int rand32()
	{
		return(rand_holder<void>::rand_seed = rand_holder<void>::rand_seed * 214013 + 2531011);
	}
/*
	template <class Proxy>
	struct xor_shift_holder
	{
		static int x;
		static int y;
		static int z;
		static int w;
	};

	template <class T> int xor_shift_holder<T>::x = 0;
	template <class T> int xor_shift_holder<T>::y = 0;
	template <class T> int xor_shift_holder<T>::z = 0;
	template <class T> int xor_shift_holder<T>::w = 0;

	inline int xor_rand()
	{
		const int t = xor_shift_holder<void>::x ^ (xor_shift_holder<void>::x << 11);
		xor_shift_holder<void>::x = xor_shift_holder<void>::y;
		xor_shift_holder<void>::y = xor_shift_holder<void>::z;
		xor_shift_holder<void>::z = xor_shift_holder<void>::w;
		xor_shift_holder<void>::w ^= (xor_shift_holder<void>::w >> 19) ^ (t ^ (t >> 8));
		return xor_shift_holder<void>::w;
	}
*/
}


inline void srand( int seed )
	{
		internal::rand_holder<void>::rand_seed = seed;
	}

inline int rand()
	{
		return internal::rand();
	}

inline int rand( int n )
	{
		FC_ASSERT(n != 0);
		return internal::rand() % n;
	}

inline int rand( int low, int high )
	{
		//FC_ASSERT(high >= low);
		return low + (internal::rand() % (( 1 + high ) - low ));
	}

inline float randf()
	{
		return internal::rand() * FC_INV_RAND_MAX;
	}

inline float randf( float n )
	{
		return (internal::rand() * FC_INV_RAND_MAX) * n;
	}

inline float randf( float low, float high )
	{
		return (internal::rand() * FC_INV_RAND_MAX) * (high - low) + low;
	}

inline float randn( float mean = 0.f, float deviation = 1.f )
	{
		//fixme: ...
		float dist = fast_sqrt( -2.f * logf(randf()) );
		float angle = randf( FC_TWOPI );

		return dist * fast_sin(angle) * deviation + mean;
	}

inline void circular_rand( float &x, float &y )
	{
		float angle = randf( FC_TWOPI );
		fast_sincos( angle, y, x );
	}

inline void circular_rand( float radius, float &x, float &y )
	{
		float angle = randf(FC_TWOPI) - FC_PI;
		fast_sincos( angle, y, x );
		x *= radius;
		y *= radius;
	}

inline void arc_rand( float minAngle, float maxAngle, float &x, float &y )
	{
		float angle = randf( minAngle, maxAngle );
		fast_sincos( angle, y, x );
	}

inline void arc_rand( float minAngle, float maxAngle, float radius, float &x, float &y )
	{
		float angle = randf( minAngle, maxAngle );
		fast_sincos( angle, y, x );
		x *= radius;
		y *= radius;
	}

inline int variance( int variant )
	{
		return rand( -variant, variant );
	}

inline int variance( int n, int variant )
	{
		return n + rand( -variant, variant );
	}

inline float variance( float variant )
	{
		return randf( -variant, variant );
	}

inline float variance( float n, float variant )
	{
		return n + randf( -variant, variant );
	}

inline bool probability( int percent )
	{
		return (rand(100) < percent);
	}

inline bool probability( int percent, int total )
	{
		return (rand(total) < percent );
	}

template <class T> inline
	const T& choose( const T& a, const T& b )
	{
		int r = rand(2);
		if( r == 0 ) return a;
		return b;
	}

template <class T> inline
	const T& choose( const T& a, const T& b, const T& c )
	{
		int r = rand(3);
		if( r == 0 ) return a;
		if( r == 1 ) return b;
		return c;
	}

template <class T> inline
	const T& choose( const T& a, const T& b, const T& c, const T& d )
	{
		int r = rand(4);
		if( r == 0 ) return a;
		if( r == 1 ) return b;
		if( r == 2 ) return c;
		return d;
	}

template <class RandomAccessIterator, class RandomNumberGenerator> inline
  void random_shuffle( RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& r )
	{
		ptrdiff_t n = last - first;
		for( ptrdiff_t i = n - 1; i > 0; --i )
			fc::swap( first[i], first[r(i + 1)] );
	}
/*
template <class RandomAccessIterator> inline
  void random_shuffle( RandomAccessIterator first, RandomAccessIterator last )
	{
		fc::random_shuffle2( first, last, fc::rand );
	}
*/

FC_NAMESPACE_END
